package com.fzy.common.excel;

import com.fzy.common.bean.BeanUtil;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * Excel导入工具类 设计思想：先把所有数据从Excel一次读取到实体类集合，然后再去检验每一个实体类数据格式是否正确
 *
 * @author 冯赵杨
 * @date 2012-11-30
 */
public class ExcelImportUtil {
    private ExcelImportUtil() {
    }

    private static final Logger LOGGER = LoggerFactory.getLogger(ExcelImportUtil.class);

    public static Workbook create(InputStream in) throws IOException, InvalidFormatException {
        if (!in.markSupported()) {
            in = new PushbackInputStream(in, 8);
        }
        if (POIFSFileSystem.hasPOIFSHeader(in)) {
            return new HSSFWorkbook(in);
        }
        if (DocumentFactoryHelper.hasOOXMLHeader(in)) {
            return new XSSFWorkbook(OPCPackage.open(in));
        }
        throw new IllegalArgumentException("你的excel版本目前poi解析不了");
    }

    /**
     * 导入Excel 方案一： Excel数据导入到实体类
     *
     * @param inputStream excel输入流
     * @param entityClass 实体类 必须有两个属性 row， column
     * @param fields      需要填充的实体类字段数组，根据字段的多少按顺序来读取excel的列数
     *                    例如 对象是User 要填充的字段写成 username,password,要和User对象中的对应
     * @param sheetIndex  第几个sheet 从0开始
     * @author 冯赵杨
     * @date 2016年12月7日 上午9:53:03
     */
    public static <T> List<T> readDataFromExcel(InputStream inputStream, Class<T> entityClass, String[] fields, int sheetIndex) {
        List<T> list = new ArrayList<T>();

        try {
            Workbook wb = create(inputStream);
            // 取sheet
            Sheet sheet = wb.getSheetAt(sheetIndex);
            for (int i = 0; i < sheet.getLastRowNum(); i++) {
                T object = entityClass.newInstance();
                // 取sheet内的第i+1行开始读取数据
                Row row = sheet.getRow(i + 1);

                //判断当前行是否为空
                if (checkRowNull(row) >= 1) {
                    break;
                }

                for (int j = 0; j < fields.length; j++) {
                    String fieldName = fields[j];
                    Cell cell = row.getCell(j);
                    String result = getCellString(cell);
                    BeanUtil.setProperty(object, fieldName, result == null ? "" : result.trim());

                    // 第几列
                    BeanUtil.setProperty(object, "column", j);
                }

                // 第几行
                BeanUtil.setProperty(object, "row", i + 1);

                list.add(object);

            }

        } catch (Exception e) {
            LOGGER.error("导入excel文件出错", e);
        }

        return list;

    }

    /**
     * 导入Excel 方案二： Excel数据导入到Map
     *
     * @param inputStream 输入流
     * @param fields      需要导入的字段数组 根据字段的多少按顺序来读取excel的列数
     * @param sheetIndex  第几个sheet 从0开始
     * @author 冯赵杨
     * @date 2016年12月7日 上午9:54:27
     */
    public static List<Map<String, String>> readDataFromExcel(InputStream inputStream, String[] fields,
                                                              int sheetIndex) {
        List<Map<String, String>> list = new ArrayList<>();
        Workbook wb;
        Sheet sheet;
        try {
            wb = create(inputStream);

            // 取sheet
            sheet = wb.getSheetAt(sheetIndex);
            for (int i = 0; i < sheet.getLastRowNum(); i++) {
                // 取sheet内的第i+1行开始读取数据
                int startRow = i + 1;
                Map<String, String> map = new HashMap<>();
                Row row = sheet.getRow(startRow);

                //判断当前行是否为空
                if (checkRowNull(row) >= 1) {
                    break;
                }

                for (int j = 0; j < fields.length; j++) {
                    String fieldName = fields[j];
                    Cell cell = row.getCell(j);
                    String result = getCellString(cell);
                    map.put(fieldName, result == null ? "" : result.trim());
                }

                // 第几行
                map.put("row", startRow + 1 + "");

                list.add(map);
            }

        } catch (Exception e) {
            LOGGER.error("导入excel文件出错", e);
        }

        return list;
    }


    /**
     * 判断当前行是否为空
     *
     * @author 冯赵杨
     * @date 2018年1月25日 下午4:46:43
     */
    private static int checkRowNull(Row row) {
        int num = 0;
        Cell c = row.getCell(0);
        if (c.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
            num++;
        }

		/*Iterator<Cell> cellItr = hssfRow.iterator();
		while (cellItr.hasNext()) {
			Cell c = cellItr.next();
			if (c.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
				num++;
			}
		}*/
        return num;
    }

    /**
     * 转换表格cell的值类型
     */
    private static String getCellString(Cell cell) {
        String result = "";

        if (cell == null) {
            return result;
        }


        switch (cell.getCellTypeEnum()) {
            // 数字型
            case NUMERIC:
                // 数字时间型
                if (HSSFDateUtil.isCellDateFormatted(cell)) {
                    short format = cell.getCellStyle().getDataFormat();
                    SimpleDateFormat df;
                    if (format == 14 || format == 31 || format == 57 || format == 58) {
                        // 短日期
                        df = new SimpleDateFormat("yyyy-MM-dd");
                    } else if (format == 20 || format == 32) {
                        // 时间
                        df = new SimpleDateFormat("HH:mm");
                    } else {
                        // 长日期
                        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    }

                    double value = cell.getNumericCellValue();
                    Date date = DateUtil.getJavaDate(value);
                    result = df.format(date);
                } else {
                    DecimalFormat df = new DecimalFormat("################.####");
                    result = df.format(cell.getNumericCellValue());
                }
                break;
            // 字符型
            case STRING:
                result = cell.getStringCellValue();
                break;
            // boolean型
            case BOOLEAN:
                result = cell.getBooleanCellValue() ? "0" : "1";
                break;
            // 公式
            case FORMULA:
                result = String.valueOf(cell.getCellFormula());
                break;
            case BLANK:
                result = "";
                break;
            default:
                result = "";
                break;
        }
        return result;
    }

}
